package DRC.DRModbus;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import DRC.DRCDB;
import DRC.channel;
import DRC.channel4collect;
import DRC.dataItem;
import DRC.dataItem4collect;
import DRCOMM.DRHTTP_API;
import DRCOMM.DR_SESSION;
import DRCOMM.FJW_URI;
import DRCOMM.dr_ajax_answer;
import DRCOMM.dr_util;
import DRCOMM.record_data_set;
import com.fazecast.jSerialComm.SerialPort;

public class DRModbus_TCP_Master extends Thread{

    // 定义常量
    final public static int REGISTER_TYPE_COILS = 1;
    final public static int REGISTER_TYPE_DISCRETE_INPUTS = 2;
    final public static int REGISTER_TYPE_HOLDING_REGISTERS = 3;
    final public static int REGISTER_TYPE_INPUT_REGISTERS = 4;

    final public static int DATA_SINGED = 1;
    final public static int DATA_LONG = 2;
    final public static int DATA_FLOAT = 3;
    final public static int DATA_DOUBLE = 4;

    DRCDB drcdb;
    public String host_ip=null;
    public int port=0;
    public int channel_id;
    // public int buffSize=1024;
    public byte[] recive_buff=new byte[2048];
    // public byte[] send_buff=new byte[2048];
    public boolean runMark=true;   //运行标志
    public int run_cycle=3;        //采集周期变量
    public String name="";
    public int function_code=3;
    public int slave_id=1;
    public int address=0;
    public int count=0;
    public int dataitem_type=1;
    private static int max_group_size=100;

    private static String logPrefix = "./log/Modbus/ModbusTCPMaster_";

    public static ArrayList<channel> channels=null;
    public static ArrayList<channel4collect> channels4collect=null;

    public DRModbus_TCP_Master(String host_ip,int port){
        this.host_ip=host_ip;
        this.port=port;
    }

    public DRModbus_TCP_Master(DRCDB drcdb,
                               String host_ip,int port,int channel_id,String name,
                               int function_code,int slave_id,int address,int count,
                               int dataitem_type,int run_cycle){
        this.drcdb=drcdb;
        this.host_ip=host_ip;
        this.port=port;
        this.channel_id=channel_id;
        this.name=name;
        this.function_code=function_code;
        this.slave_id=slave_id;
        this.address=address;
        this.count=count;
        this.dataitem_type=dataitem_type;
        this.run_cycle=run_cycle;
    }

    public static List<Byte> execute2Bytes(
            String host,int port,int function_code,int slaveID,int address,int quantity_of_x) throws Exception
    {
        if((function_code==3||function_code==4)&&quantity_of_x>max_group_size){
            throw new SocketException();
        }
        List<Byte> result;
        String response;
        byte[] recive_buff;
        if(function_code==1||function_code==2){
            if(quantity_of_x<=max_group_size/16){
                recive_buff=new byte[(int) (9+Math.ceil(quantity_of_x/8.0f))];
            }else{
                recive_buff=new byte[(int) (9+Math.ceil(max_group_size/8.0f))];
            }
        }else{
            if(quantity_of_x<=max_group_size){
                recive_buff=new byte[9+quantity_of_x*2];
            }else{
                recive_buff=new byte[9+max_group_size*2];
            }
        }
        try {
            Socket socket=new Socket(host,port);
            //获取Socket的输出流，用来向Slave端发送数据
            DataOutputStream out = new DataOutputStream (socket.getOutputStream());
            //获取Socket的输入流，用来接收从Slave端发送过来的数据
            DataInputStream in = new DataInputStream(socket.getInputStream());
            int event_id=1;  //event_id始终置1，每次均为一次通信，后续根据情况修改 2022年8月7日 罗继东
            int protocol=0;  //modbus tcp协议为 00 00
            int length=6;    //01-04请求帧 功能码+数据长度均为6，1字节功能码
            result=new ArrayList<Byte>();
            result.add((byte)(event_id/256));           //事务处理标识 H
            result.add((byte)(event_id%256));           //事务处理标识 L
            result.add((byte)(protocol/256));           //协议标识 H 
            result.add((byte)(protocol%256));           //协议标识 L
            result.add((byte)(length/256));             //长度 H
            result.add((byte)(length%256));             //长度 L
            result.add((byte)(slaveID%256));            //单元标识符
            result.add((byte)(function_code));          //功能码 
            result.add((byte)(address/256));            //地址 H
            result.add((byte)(address%256));            //地址 L
            result.add((byte)(quantity_of_x/256));      //数量 H
            result.add((byte)(quantity_of_x%256));      //数量 L
            // 向 Slave 端输出请求
            byte[] msg=dr_util.ListToBytes(result);
            //请求报文日志
            write_log(1,host,String.valueOf(port),msg,msg.length);
            out.write(msg);
            // 显示接收、发送内容
            int data_length=in.read(recive_buff);
            response=dr_util.bytes2hexstr(dr_util.ListToBytes(result));
            //回复报文日志
            int receiveLength = dr_util.byteToInt(recive_buff[5])+6;
            byte[] trueReceive = new byte[receiveLength];
            System.arraycopy(recive_buff,0,trueReceive,0,receiveLength);
            write_log(0,host,String.valueOf(port),trueReceive,receiveLength);
            System.out.println(String.format("Slave send message:[%s]",response));
            out.close();
            socket.close();
            if(function_code==3||function_code==4){
                if(data_length!=(9+quantity_of_x*2)){
                    throw new SocketException();
                }
            }
            return dr_util.BytesToList(recive_buff);
        } catch (Exception e) {
            // e.printStackTrace();
            throw new SocketException();
        }
        // return dr_util.ListToBytes(result);
        // return dr_util.BytesToList(recive_buff);
    }

    @FJW_URI(value ="channel4collect/sendModbus")
    public static DRHTTP_API sendModbus(DRCDB drcdb,String URI){
        return new DRHTTP_API(drcdb,URI){
            @Override
            public String getResult(Map<String, Object> parameters,DR_SESSION drs) {
                String host = parameters.get("host_ip").toString();
                String port = parameters.get("port").toString();
                String com = parameters.get("com").toString();
                String band_rate = parameters.get("band_rate").toString();
                String parity = parameters.get("parity").toString();
                String stop = parameters.get("stop").toString();
                String protocol = parameters.get("protocol").toString();
                String function_code = parameters.get("register_type").toString();
                String dataType = parameters.get("data_type").toString();
                String slaveID = parameters.get("slave_id").toString();
                String address = parameters.get("address").toString();
                String IntervalTime = parameters.get("IntervalTime").toString();
                String data = parameters.get("data").toString();
                int intFunctionCode = 0;
                switch (function_code){
                    case "写线圈":
                        intFunctionCode = 5;
                        break;
                    case "写保持寄存器":
                        intFunctionCode = 6;
                        break;
                    case "写多个线圈":
                        intFunctionCode = 15;
                        break;
                    case "写多个保持寄存器":
                        intFunctionCode = 16;
                        break;
                }

                String[] strArray = data.split("[,，]");
                int[] intArray = new int[0];
                switch (dataType){
                    case "1":
                        intArray=new int[strArray.length];
                        byte[] bytes = new byte[2];
                        for (int i = 0; i < intArray.length; i++) {
                            if(Integer.parseInt(strArray[i].trim())>=0) {
                                bytes[0] = (byte) (Integer.parseInt(strArray[i].trim()) & 0xFF);
                                bytes[1] = (byte) ((Integer.parseInt(strArray[i].trim()) >> 8) & 0xFF);
                                intArray[i] = bytes[0] * 256 + bytes[1];
                            }else{
                                int num = 32768+Integer.parseInt(strArray[i].trim());
                                bytes[0] = (byte) (num & 0xFF );
                                bytes[1] = (byte) (( num >> 8) & 0xFF|0x80);
                                intArray[i] = bytes[0] * 256 + bytes[1];
                            }
                        }
                        break;
                    case "2":
                        intArray=new int[strArray.length];
                        for (int i = 0; i < strArray.length; i++) {
                            if(Integer.parseInt(strArray[i].trim())>=0) {
                                intArray[i] = Integer.parseInt(strArray[i].trim());
                            }else{
                                int num = 32768+Integer.parseInt(strArray[i].trim());
                                intArray[i] = num |0x8000;
                            }
                        }
                        break;
                    case "3":
                        intArray=new int[strArray.length*2];
                        for (int i = 0; i < strArray.length; i++) {
                            Float floatValue = Float.parseFloat(strArray[i].trim());
                            int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                            intArray[i*2] = value_list[0]*256+value_list[1];
                            intArray[i*2+1] = value_list[2]*256+value_list[3];
                        }
                        break;
                    case "4":
                        intArray=new int[strArray.length*2];
                        for (int i = 0; i < strArray.length; i++) {
                            Float floatValue = Float.parseFloat(strArray[i].trim());
                            int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                            intArray[i*2] = value_list[2]*256+value_list[3];
                            intArray[i*2+1] = value_list[0]*256+value_list[1];
                        }
                        break;
                    case "5":
                        intArray=new int[strArray.length*2];
                        for (int i = 0; i < strArray.length; i++) {
                            Float floatValue = Float.parseFloat(strArray[i].trim());
                            int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                            intArray[i*2] = value_list[1]*256+value_list[0];
                            intArray[i*2+1] = value_list[3]*256+value_list[2];
                        }
                        break;
                    case "6":
                        intArray=new int[strArray.length*2];
                        for (int i = 0; i < strArray.length; i++) {
                            Float floatValue = Float.parseFloat(strArray[i].trim());
                            int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                            intArray[i*2] = value_list[3]*256+value_list[2];
                            intArray[i*2+1] = value_list[1]*256+value_list[0];
                        }
                        break;
                    case "7":
                        intArray=new int[strArray.length];
                        for (int i = 0; i < strArray.length; i++) {
                            intArray[i] = Integer.parseInt(strArray[i].trim());
                        }
                        break;
                }

                try {
                    if ("Modbus TCP".equals(protocol)) {
                        DRModbus_TCP_Master.execute2Bytes4W(host, Integer.parseInt(port), intFunctionCode, Integer.parseInt(slaveID), Integer.parseInt(address), intArray);
                    } else if ("Modbus RTU".equals(protocol)) {
                        SerialPort sp = null;
                        sp = SerialPort.getCommPort(com);
                        DRModbus_RTU_Master.execute2Bytes4W(sp,intFunctionCode,Integer.parseInt(slaveID),Integer.parseInt(address),intArray,com,band_rate,parity,stop,Integer.parseInt(IntervalTime));
                    }
                }catch (Exception e){
                    return dr_ajax_answer.sample_json_string(1,"下发出现异常");
                }
                return dr_ajax_answer.sample_json_string(0,"");
            }
        };
    }

    public static String sendModbus(String host,String port,String com,String band_rate,String parity,String stop,String protocol,String function_code,String dataType,String slaveID,String address,String data){
        int intFunctionCode = 0;
        switch (function_code){
            case "写线圈":
                intFunctionCode = 5;
                break;
            case "写保持寄存器":
                intFunctionCode = 6;
                break;
            case "写多个线圈":
                intFunctionCode = 15;
                break;
            case "写多个保持寄存器":
                intFunctionCode = 16;
                break;
        }

        String[] strArray = data.split("[,，]");
        int[] intArray = new int[0];
        switch (dataType){
            case "1":
                intArray=new int[strArray.length];
                byte[] bytes = new byte[2];
                for (int i = 0; i < intArray.length; i++) {
                    bytes[0] = (byte) (Integer.parseInt(strArray[i].trim()) & 0xFF);
                    bytes[1] = (byte) ((Integer.parseInt(strArray[i].trim()) >> 8) & 0xFF);
                    intArray[i] = bytes[0]*256+bytes[1];
                }
                break;
            case "2":
                intArray=new int[strArray.length];
                for (int i = 0; i < strArray.length; i++) {
                    intArray[i] = Integer.parseInt(strArray[i].trim());
                }
                break;
            case "3":
                intArray=new int[strArray.length*2];
                for (int i = 0; i < strArray.length; i++) {
                    Float floatValue = Float.parseFloat(strArray[i].trim());
                    int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                    intArray[i*2] = value_list[0]*256+value_list[1];
                    intArray[i*2+1] = value_list[2]*256+value_list[3];
                }
                break;
            case "4":
                intArray=new int[strArray.length*2];
                for (int i = 0; i < strArray.length; i++) {
                    Float floatValue = Float.parseFloat(strArray[i].trim());
                    int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                    intArray[i*2] = value_list[2]*256+value_list[3];
                    intArray[i*2+1] = value_list[0]*256+value_list[1];
                }
                break;
            case "5":
                intArray=new int[strArray.length*2];
                for (int i = 0; i < strArray.length; i++) {
                    Float floatValue = Float.parseFloat(strArray[i].trim());
                    int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                    intArray[i*2] = value_list[1]*256+value_list[0];
                    intArray[i*2+1] = value_list[3]*256+value_list[2];
                }
                break;
            case "6":
                intArray=new int[strArray.length*2];
                for (int i = 0; i < strArray.length; i++) {
                    Float floatValue = Float.parseFloat(strArray[i].trim());
                    int[] value_list=dr_util.float_to_IEEE_STD_754(floatValue);
                    intArray[i*2] = value_list[3]*256+value_list[2];
                    intArray[i*2+1] = value_list[1]*256+value_list[0];
                }
                break;
            case "7":
                intArray=new int[strArray.length];
                for (int i = 0; i < strArray.length; i++) {
                    intArray[i] = Integer.parseInt(strArray[i].trim());
                }
                break;
        }

        try {
            if ("Modbus TCP".equals(protocol)) {
                DRModbus_TCP_Master.execute2Bytes4W(host, Integer.parseInt(port), intFunctionCode, Integer.parseInt(slaveID), Integer.parseInt(address), intArray);
            } else if ("Modbus RTU".equals(protocol)) {
                SerialPort sp = null;
                sp = SerialPort.getCommPort(com);
                DRModbus_RTU_Master.execute2Bytes4W(sp,intFunctionCode,Integer.parseInt(slaveID),Integer.parseInt(address),intArray,com,band_rate,parity,stop);
            }
        }catch (Exception e){
            return dr_ajax_answer.sample_json_string(1,"下发出现异常");
        }
        return dr_ajax_answer.sample_json_string(0,"");
    }

    // 针对写入指令（遥控/遥调）的执行指令转字节
    public static List<Byte> execute2Bytes4W(
            String host,int port,int function_code,int slaveID,int address,int[] data) throws Exception
    {
        if((function_code==0x10)&&data.length>max_group_size){
            throw new SocketException();
        }
        List<Byte> result;
        String response;
        try {
            Socket socket=new Socket(host,port);
            //获取Socket的输出流，用来向Slave端发送数据
            DataOutputStream out = new DataOutputStream (socket.getOutputStream());
            //获取Socket的输入流，用来接收从Slave端发送过来的数据
            DataInputStream in = new DataInputStream(socket.getInputStream());
            int event_id=1;  //event_id始终置1，每次均为一次通信，后续根据情况修改 2022年8月7日 罗继东
            int protocol=0;  //modbus tcp协议为 00 00
            int length;
            result=new ArrayList<Byte>();
            if(function_code==5){
                length=6;    //05请求帧 功能码+数据长度均为6，1字节功能码
                result.add((byte)(event_id/256));           //事务处理标识 H
                result.add((byte)(event_id%256));           //事务处理标识 L
                result.add((byte)(protocol/256));           //协议标识 H
                result.add((byte)(protocol%256));           //协议标识 L
                result.add((byte)(length/256));             //长度 H
                result.add((byte)(length%256));             //长度 L
                result.add((byte)(slaveID%256));            //单元标识符
                result.add((byte)(function_code));          //功能码
                result.add((byte)(address/256));            //地址 H
                result.add((byte)(address%256));            //地址 L
                if((data[0]&0x01)==0){
                    result.add((byte)(0x00));               //OFF H
                    result.add((byte)(0x00));               //OFF L
                }else{
                    result.add((byte)(0xFF));               //ON H
                    result.add((byte)(0x00));               //ON L
                }
            }else if(function_code==0x0F){
                length=7+(int)Math.ceil(data.length/8.0f);    //0F请求帧 功能码+数据长度=7+数据量/8
                result.add((byte)(event_id/256));           //事务处理标识 H
                result.add((byte)(event_id%256));           //事务处理标识 L
                result.add((byte)(protocol/256));           //协议标识 H
                result.add((byte)(protocol%256));           //协议标识 L
                result.add((byte)(length/256));             //长度 H
                result.add((byte)(length%256));             //长度 L
                result.add((byte)(slaveID%256));            //单元标识符
                result.add((byte)(function_code));          //功能码
                result.add((byte)(address/256));            //地址 H
                result.add((byte)(address%256));            //地址 L
                result.add((byte)(data.length/256));      //数量 H
                result.add((byte)(data.length%256));      //数量 L
                result.add((byte)(Math.ceil(data.length/8.0f)));            //字节长度
                // 将data数组转换为字节数组
                int[] data_byte=new int[1+data.length/8];
                for(int i=0;i<(int)Math.ceil(data.length/8.0f);i++){
                    data_byte[i]=0;
                    for(int j=0;j<8&&(i*8+j)<data.length;j++){
                        if(data[i*8+j]!=0){
                            data_byte[i]=data_byte[i]|(0x01<<j);
                        }
                    }
                }
                for(int i=0;i<(int)Math.ceil(data.length/8.0f);i++){
                    result.add((byte)(data_byte[i]));
                }
            }else if(function_code==6){
                length=6;    //06请求帧 功能码+数据长度均为6，1字节功能码
                result.add((byte)(event_id/256));           //事务处理标识 H
                result.add((byte)(event_id%256));           //事务处理标识 L
                result.add((byte)(protocol/256));           //协议标识 H
                result.add((byte)(protocol%256));           //协议标识 L
                result.add((byte)(length/256));             //长度 H
                result.add((byte)(length%256));             //长度 L
                result.add((byte)(slaveID%256));            //单元标识符
                result.add((byte)(function_code));          //功能码
                result.add((byte)(address/256));            //地址 H
                result.add((byte)(address%256));            //地址 L
                result.add((byte)(data[0]/256));            //数值 H
                result.add((byte)(data[0]%256));            //数值 L
            }else if(function_code==16){
                length=7+data.length*2;         //10请求帧 功能码+数据长度=7+数据量*2
                result.add((byte)(event_id/256));           //事务处理标识 H
                result.add((byte)(event_id%256));           //事务处理标识 L
                result.add((byte)(protocol/256));           //协议标识 H
                result.add((byte)(protocol%256));           //协议标识 L
                result.add((byte)(length/256));             //长度 H
                result.add((byte)(length%256));             //长度 L
                result.add((byte)(slaveID%256));            //单元标识符
                result.add((byte)(function_code));          //功能码
                result.add((byte)(address/256));            //地址 H
                result.add((byte)(address%256));            //地址 L
                result.add((byte)(data.length/256));      //数量 H
                result.add((byte)(data.length%256));      //数量 L
                result.add((byte)(data.length*2));            //字节长度
                for(int i=0;i<data.length;i++){
                    result.add((byte)(data[i]/256));            //数值 H
                    result.add((byte)(data[i]%256));            //数值 L
                }
            }
            // 向 Slave 端输出请求
            byte[] msg=dr_util.ListToBytes(result);
            System.out.println(String.format("client send message:[%s]",dr_util.bytes2hexstr(msg)));
            out.write(msg);
            //请求报文日志
            write_log(1,host,String.valueOf(port),msg,msg.length);
            // 显示接收、发送内容
            byte[] recive_buff=new byte[512];
            int data_length=in.read(recive_buff);
            response=dr_util.bytes2hexstr(recive_buff,data_length);
            //回复报文日志
            int receiveLength = dr_util.byteToInt(recive_buff[5])+6;
            byte[] trueReceive = new byte[receiveLength];
            System.arraycopy(recive_buff,0,trueReceive,0,receiveLength);
            write_log(0,host,String.valueOf(port),trueReceive,receiveLength);
            System.out.println(String.format("Slave send message:[%s]",response));
            out.close();
            socket.close();
            return dr_util.BytesToList(recive_buff);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SocketException();
        }
        // return dr_util.ListToBytes(result);
        // return dr_util.BytesToList(recive_buff);
    }

    /**
     * 读取Slave数据为list
     * @param host  Slave主机地址
     * @param port  Slave主机端口
     * @param function_code 功能码
     * @param slaveID
     * @param address 读取起始地址
     * @param quantity_of_x 数量
     * @return 返回值为读取到数据的List，注意为2个字节
     * @throws SocketException
     */
    public static List<byte[]> read_slave_data2byte2(String host,int port,int function_code,int slaveID,int address,int quantity_of_x) throws SocketException{
        List<byte[]> result=new ArrayList<byte[]>();
        byte[] data;
        List<Byte> slave_data;
        int group_index;
        try {
            if(function_code==1||function_code==2){
                for(group_index=0;group_index*max_group_size*16<quantity_of_x;group_index++){
                    if((quantity_of_x-(group_index*max_group_size*16))<max_group_size*16){
                        slave_data=DRModbus_TCP_Master.execute2Bytes(
                                host,port,
                                function_code, slaveID, address+group_index*max_group_size, (quantity_of_x-(group_index*max_group_size*16))
                        );
                        for(int i=0;i<(quantity_of_x-(group_index*max_group_size*16));i++){
                            if((9+i/8)>slave_data.size())break;
                            data=new byte[1];
                            data[0]=slave_data.get(9+i/8);
                            data[0]=(byte) ((data[0]>>(i%8))&0x01);
                            result.add(data);
                        }
                    }else{
                        slave_data=DRModbus_TCP_Master.execute2Bytes(
                                host,port,
                                function_code, slaveID, address+group_index*max_group_size, max_group_size*16
                        );
                        for(int i=0;i<max_group_size*16;i++){
                            if((9+i/8)>slave_data.size())break;
                            data=new byte[1];
                            data[0]=slave_data.get(9+i/8);
                            data[0]=(byte) (data[0]>>(i%8));
                            result.add(data);
                        }
                    }
                }
            }else{
                for(group_index=0;group_index*max_group_size<quantity_of_x;group_index++){
                    if((quantity_of_x-(group_index*max_group_size))<max_group_size){
                        slave_data=DRModbus_TCP_Master.execute2Bytes(
                                host,port,
                                function_code, slaveID, address+group_index*max_group_size, (quantity_of_x-(group_index*max_group_size))
                        );
                        for(int i=0;i<(quantity_of_x-(group_index*max_group_size));i++){
                            if((10+i*2)>slave_data.size())break;
                            data=new byte[2];
                            data[0]=slave_data.get(9+i*2);
                            data[1]=slave_data.get(10+i*2);
                            result.add(data);
                        }
                    }else{
                        slave_data=DRModbus_TCP_Master.execute2Bytes(
                                host,port,
                                function_code, slaveID, address+group_index*max_group_size, max_group_size
                        );
                        for(int i=0;i<max_group_size;i++){
                            if((10+i*2)>slave_data.size())break;
                            data=new byte[2];
                            data[0]=slave_data.get(9+i*2);
                            data[1]=slave_data.get(10+i*2);
                            result.add(data);
                        }
                    }
                }
            }
        } catch (Exception e) {
            return null;
        }
        return result;
    }

    public static List<byte[]> read_slave_data2byte4(String host,int port,int function_code,int slaveID,int address,int quantity_of_x){
        List<byte[]> result=new ArrayList<byte[]>();
        byte[] data;
        List<Byte> slave_data;
        int group_index;
        try {
            for(group_index=0;group_index*max_group_size<quantity_of_x;group_index++){
                if((quantity_of_x-(group_index*max_group_size))<max_group_size){
                    slave_data=DRModbus_TCP_Master.execute2Bytes(
                            host,port,
                            function_code, slaveID, address+group_index*max_group_size, (quantity_of_x-(group_index*max_group_size))
                    );
                    for(int i=0;i<(quantity_of_x-(group_index*max_group_size));i+=2){
                        data=new byte[4];
                        data[0]=slave_data.get(9+i*2);
                        data[1]=slave_data.get(10+i*2);
                        data[2]=slave_data.get(11+i*2);
                        data[3]=slave_data.get(12+i*2);
                        result.add(data);
                    }
                }else{
                    slave_data=DRModbus_TCP_Master.execute2Bytes(
                            host,port,
                            function_code, slaveID, address+group_index*max_group_size, max_group_size
                    );
                    for(int i=0;i<max_group_size;i+=2){
                        data=new byte[4];
                        data[0]=slave_data.get(9+i*2);
                        data[1]=slave_data.get(10+i*2);
                        data[2]=slave_data.get(11+i*2);
                        data[3]=slave_data.get(12+i*2);
                        result.add(data);
                    }
                }
            }
        } catch (Exception e) {
            return null;
        }
        return result;
    }

    public String execute(int function_code,int slaveID,int address,int quantity_of_x){
        List<Byte> result=new ArrayList<Byte>();
        String response="";
        try {
            result=DRModbus_TCP_Master.execute2Bytes(this.host_ip,this.port,function_code, slaveID, address, quantity_of_x);
            // 显示接收、发送内容
            response=dr_util.bytes2hexstr(dr_util.ListToBytes(result));
            System.out.println(String.format("Slave send message:[%s]",response));
            return response;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // return dr_util.ListToBytes(result);
        return response;
    }

    public static String read_modbus_data(String host,String port,String function_code,String slave_id,
                                          String address,String count){
        String result="";
        String content="";
        try {
            DRModbus_TCP_Master dcm=new DRModbus_TCP_Master(host, Integer.parseInt(port));
            result=dcm.execute(Integer.parseInt(function_code),
                    Integer.parseInt(slave_id),Integer.parseInt(address), Integer.parseInt(count));
            content=dr_ajax_answer.sample_json_string(0,result.substring(27));
        } catch (Exception e) {
            content=dr_ajax_answer.sample_json_string(1,"读取失败");
        }
        return content;
    }

    /**
     * 关联WEB API列表
     * @param api_lists
     * @param drcdb
     */
    public static void associate_actions(List<DRHTTP_API> api_lists,DRCDB drcdb) throws ClassNotFoundException{
        @SuppressWarnings("unchecked")
        Class<?> CLS=(Class<DRModbus_TCP_Master>) Class.forName("DRC.DRModbus.DRModbus_TCP_Master");
        for(Method method:CLS.getDeclaredMethods()){
            FJW_URI fjw_uri=method.getAnnotation(FJW_URI.class);
            System.out.println(method.toString());
            if(fjw_uri!=null){
                System.out.println(method.toString());
                System.out.println(fjw_uri.value());
                try {
                    api_lists.add((DRHTTP_API)method.invoke(CLS,drcdb, fjw_uri.value()));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @FJW_URI(value ="modbus/read_modbus_data")
    public static DRHTTP_API read_modbus_data(DRCDB drcdb,String URI){
        return new DRHTTP_API(drcdb,URI){
            @Override
            public String getResult(Map<String, Object> parameters,DR_SESSION drs){
                String result="";
                String content="";
                String host=this.get_parameters(parameters,"host");
                String port=this.get_parameters(parameters,"port");
                String function_code=this.get_parameters(parameters,"function_code");
                String slave_id=this.get_parameters(parameters,"slave_id");
                String address=this.get_parameters(parameters,"address");
                String count=this.get_parameters(parameters,"count");
                try {
                    DRModbus_TCP_Master dcm=new DRModbus_TCP_Master(host, Integer.parseInt(port));
                    result=dcm.execute(Integer.parseInt(function_code),
                            Integer.parseInt(slave_id),Integer.parseInt(address), Integer.parseInt(count));
                    content=dr_ajax_answer.sample_json_string(0,result.substring(27));
                } catch (Exception e) {
                    content=dr_ajax_answer.sample_json_string(1,"读取失败");
                }
                return content;
            }
        };
    }

    @Override
    public void run(){
        DRCDB drcdb=this.drcdb;
        String sqlstr;
        record_data_set di_rds;
        float value;
        int register_type=1;
        int data_type;
        byte[] data;
        // 暂时仅处理输入寄存器和保持寄存器
        // 2022年12月19日 罗继东
        if(this.function_code==4)
            register_type=3;
        else if(this.function_code==3)
            register_type=4;
        channel4collect ch4c=null;
        dataItem4collect di4c=null;
        for(int i=0;i<channels4collect.size();i++){
            if(channels4collect.get(i).channel_id==this.channel_id){
                ch4c=channels4collect.get(i);
                break;
            }
        }
        while(this.runMark&&ch4c!=null){
            try {
                List<byte[]> slave_data=DRModbus_TCP_Master.read_slave_data2byte2(
                        this.host_ip,this.port,this.function_code,this.slave_id,this.address,this.count
                );
                sqlstr="select dataItem_id,label,address,data_type,coefficient,negation,BCD,ABS,base_value from dataItem4collect";
                sqlstr+=" where channel_id="+this.channel_id;
                di_rds=drcdb.executeQuerySQL(sqlstr);
                try{
                    for(int di_index=0;di_index<ch4c.ds4c.size();di_index++){
                        di4c=ch4c.ds4c.get(di_index);
                        data_type=di4c.data_type;
                        if(di_index==(ch4c.ds4c.size()-1)&&data_type>2&&data_type<7)break;
                        value=0;
                        switch (data_type){
                            case 1:
                                value=dr_util.byte2toshort_s(slave_data.get(
                                        di4c.address-address
                                ));
                                break;
                            case 2:
                                value=dr_util.byte2toshort_b(slave_data.get(
                                        di4c.address-address
                                ));
                                break;
                            case 3:
                                data=new byte[4];
                                data[0]=slave_data.get(
                                        di4c.address-address
                                )[0];
                                data[1]=slave_data.get(
                                        di4c.address-address
                                )[1];
                                data[2]=slave_data.get(
                                        di4c.address-address+1
                                )[0];
                                data[3]=slave_data.get(
                                        di4c.address-address+1
                                )[1];
                                value=dr_util.byte4tofloat_s(data);
                                break;
                            case 4:
                                data=new byte[4];
                                data[0]=slave_data.get(
                                        di4c.address-address
                                )[0];
                                data[1]=slave_data.get(
                                        di4c.address-address
                                )[1];
                                data[2]=slave_data.get(
                                        di4c.address-address+1
                                )[0];
                                data[3]=slave_data.get(
                                        di4c.address-address+1
                                )[1];
                                value=dr_util.byte4tofloat_s2(data);
                                break;
                            case 5:
                                data=new byte[4];
                                data[0]=slave_data.get(
                                        di4c.address-address
                                )[0];
                                data[1]=slave_data.get(
                                        di4c.address-address
                                )[1];
                                data[2]=slave_data.get(
                                        di4c.address-address+1
                                )[0];
                                data[3]=slave_data.get(
                                        di4c.address-address+1
                                )[1];
                                value=dr_util.byte4tofloat_b(data);
                                break;
                            case 6:
                                data=new byte[4];
                                data[0]=slave_data.get(
                                        di4c.address-address
                                )[0];
                                data[1]=slave_data.get(
                                        di4c.address-address
                                )[1];
                                data[2]=slave_data.get(
                                        di4c.address-address+1
                                )[0];
                                data[3]=slave_data.get(
                                        di4c.address-address+1
                                )[1];
                                value=dr_util.byte4tofloat_b2(data);
                                break;
                            case 7:
                                value=slave_data.get(
                                        di4c.address-address
                                )[0];
                                break;
                            default:
                                value=0;
                        }
                        // 根据系数转换值
                        value=value*Float.parseFloat(di_rds.datas.get(di_index).get("coefficient"));
                        // 根据取反设定转换值
                        if(Integer.parseInt(di_rds.datas.get(di_index).get("negation"))==1)
                            value=-1*value;
                        // 根据绝对值设定转换值
                        if(Integer.parseInt(di_rds.datas.get(di_index).get("ABS"))==1)
                            value=Math.abs(value);
                        // 根据基值转换值
                        value=value+Float.parseFloat(di_rds.datas.get(di_index).get("base_value"));
//                        if(dataItem4collect.updateLocalDataItem(channel_id,
//                                slave_id,register_type,
//                                di4c.address,
//                                value))
//                            System.out.println(name+":"
//                                    +di_rds.datas.get(di_index).get("label")
//                                    +":写入完成！["+value+"]");
                        Date now=new Date();
                        SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss");
                        System.out.println("当前时间:"+ft.format(now));
                        if(this.dataitem_type==0){
                            di4c.value=value;
                            di4c.timestamp=new Date();
                        }
                    }
                } catch (Exception e){
                    System.out.println("数据处理失败！");
                }

            } catch (Exception e) {
                System.out.println(name+":"+host_ip+"["+port+"]连接失败！");
            }
            try {
                for(int loop_index=0;loop_index<this.run_cycle;loop_index++){
                    Thread.sleep(1000);
                    if(!this.runMark)break;
                }
            } catch (InterruptedException e) {
                // e.printStackTrace();
                System.out.println(String.format("采集通道[%s]停止！",name));
            }
        }
    }

    /**
     * 写入日志函数
     * @param direction 0:接收 1发送
     * @param indestIP  目标IP
     * @param indestPart 目标端口
     * @param data       帧内容
     * @param data_length   帧内容长度
     * @throws IOException
     */
    public static void write_log(int direction,String indestIP,String indestPart,byte[] data,int data_length) throws IOException {
        int logSwitch = Integer.parseInt(DRCDB.read_conf_with_name("log_switch", "conf.ini"));
        if(logSwitch==1) {
            //根据帧内容生成最终的buff，并写入日志文件
            String destIP = indestIP + ":" + indestPart;
            String log;
            if (direction == 0)
                log = destIP + ":RX<<" + dr_util.bytes2hexstr(data, data_length);
            else
                log = destIP + ":TX>>" + dr_util.bytes2hexstr(data, data_length);
            writeLog(log);
        }
    }

    /**
     * 写日志函数
     * @param inStr
     * @throws IOException
     */
    public static void writeLog(String inStr) throws IOException {
        //写入日志函数
        //按日期和日志前缀拼接出日志文件名，向文件尾写入输入的字符串内容
        Date dNow = new Date( );
        SimpleDateFormat ft = new SimpleDateFormat ("yyyyMMdd");

        String logFileName=logPrefix+ft.format(dNow)+".log";

        // 转换为Path对象
        Path logPath = Paths.get(logFileName);
        // 提取目录路径
        Path dirPath = logPath.getParent();
        // 检查目录是否存在，如果不存在则创建
        if (!Files.exists(dirPath)) {
            try {
                Files.createDirectories(dirPath);
                System.out.println("Modbus 目录已创建");
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }
        }

        File logFile = new File(logFileName);
        if(!logFile.exists()){
            logFile.createNewFile();
        }
        FileWriter fileWriter=new FileWriter(logFile,true);
        SimpleDateFormat ft2 = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss.SSS");
        fileWriter.write("["+ft2.format(dNow)+"]"+inStr+"\n");
        fileWriter.close();
    }

    public static void main(String[] args){
        List<Byte> result=new ArrayList<Byte>();
        try {
            result=DRModbus_TCP_Master.execute2Bytes("127.0.0.1",502,3, 1, 0, 4);
            float result_float= dr_util.byte4tofloat_b(Arrays.copyOfRange(dr_util.ListToBytes(result),9,13));
            System.out.println(result_float);
            result_float= dr_util.byte4tofloat_b(Arrays.copyOfRange(dr_util.ListToBytes(result),13,17));
            System.out.println(result_float);
            // 显示接收、发送内容
            String response=dr_util.bytes2hexstr(dr_util.ListToBytes(result));
            System.out.println(response);
        } catch (Exception e) {
        }
    }
}
